#ifndef ARRAYLIST_H_
#define ARRAYLIST_H_

//#define NDEBUG

#include <assert.h>
#include <sstream>
#include <string.h>
#include "options.h"



template<typename T>
class ArrayList {
private:
	T*  data;
    int sz;
    int cap;

public:
    ArrayList(void): data(NULL), sz(0), cap(0) {

    }

    ArrayList(ArrayList const&list) {
        sz = list.sz;
        cap = list.cap;
        data = (T*)malloc(cap * sizeof(T));
        memcpy(data, list.data, cap * sizeof(T));
    }

    ~ArrayList() {
    	if (data != NULL) {
    		free(data);
    	}
    }

    const T& operator [] (int index) const  {
    	assertexection(index >= 0 && index < sz);
    	return data[index];
    }

    T& operator [] (int index) {
    	assertexection(index >= 0 && index < sz);
    	return data[index];
    }


    inline void push(const T& elem) {
    	if (sz == cap) {
    		increaseCap();
    	}
    	data[sz++] = elem;
    }

    bool contains(int value) {
    	for (int i = 0; i < sz; i++) {
    		if (data[i] == value) {
    			return true;
    		}
    	}
    	return false;
    }

    size_t size(void) const {
    	return sz;
    }


    inline void increaseCap() {
    	if (cap == 0) {
    		cap = 2;
    		data = (T*)malloc(cap * sizeof(T));
       	} else {
       		cap = (cap*3+1) >> 1;
       		data = (T*)realloc(data, cap * sizeof(T));
       	}
    }

    void resize(int size) {
    	sz = cap = size;
    	data = (T*)realloc(data, cap * sizeof(T));
    }

    void fill(T value) {
    	for (int i = 0; i < sz; i++) {
    		data[i] = value;
    	}
    }

    void clear() {
    	sz = 0;
    }

    void fastCopy(ArrayList &a) {
        assertexection(cap == a.cap);
        sz = a.sz;
        memcpy(data, a.data, cap * sizeof(T));
    }

    string toString() {
    	ostringstream buff;
    	for (int i = 0; i < sz; i++) {
    		if (i > 0) {
    			buff << "\t";
    		}
    		buff << data[i];
    	}
    	return buff.str();
    }

    T* getData() {
    	return data;
    }

};


#endif /* ARRAYLIST_H_ */
